home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Graphics Unleashed
/
PC Graphics Unleashed.iso
/
ch14
/
blobgui.c
next >
Wrap
C/C++ Source or Header
|
1994-09-14
|
63KB
|
2,436 lines
/*
-----------------------------------------------------------------------------
BLOB MODELER
By Alfonso Hermida and Steve Anger Dates: 12/16/93 ~ 2/15/94
-----------------------------------------------------------------------------
*/
#include <dos.h>
#include <graphics.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <math.h>
#include <ctype.h>
#define TOL 0.0005
#define PI 3.14159265358979323846
#define FULLSCREEN_VIEW setviewport(0,0,getmaxx(),getmaxy(),1);
#define FRONT_ID 0
#define SIDE_ID 1
#define TOP_ID 2
#define ISO_ID 3
#define FRONT_VIEW setviewport(1, 241, 239, 478, 1);
#define SIDE_VIEW setviewport(241, 241, 478, 478,1);
#define TOP_VIEW setviewport(1, 1, 239, 239, 1);
#define ISO_VIEW setviewport(241, 1, 478, 239, 1);
#define FRONT_AREA 0
#define SIDE_AREA 1
#define TOP_AREA 2
#define ISO_AREA 3
#define MENU_AREA 4
#define TEXT_INPUT 1
#define NUMBER_INPUT 0
#define UP 1
#define DOWN 0
typedef struct {
int x,y,width,height;
int color;
char str[81];
} Icon;
typedef struct {
float x,y,z;
} POINT3D;
typedef struct {
int x,y;
} POINTint;
typedef struct {
POINT3D from, up, at;
float angle;
}Window3D;
typedef struct {
float Hmin, Vmin, Hmax, Vmax;
}WorldLimits;
typedef struct {
float x,y,z;
float radius, strength;
} BLOB;
typedef struct {
POINT3D p1, p2;
} PAIR3D;
typedef struct {
float value;
POINT3D loc;
} SAMPLE;
typedef struct {
float rmin, cmin,
rowstep,colstep,
PlaneDist;
int rows, cols;
char PerpTo;
} GRID;
// MOUSE ROUTINES
int IsMouse (void);
int MouseClick (void);
void MouseXY (int *xpos, int *ypos);
void MouseShow (int toggle);
int WhereIsMouse(int x, int y);
void UpdateMousePos(int xpos,int ypos,int status);
// ICON ROUTINES
Icon CreateIcon(int xo,int yo,int width,int height,int color,char * text);
void DrawIcon (Icon ic);
int IconCheck (Icon ikon, int xm, int ym);
void DrawIconHiLite(Icon ic, int UpDown);
void CreateIconColumn (int xo, int yo, int width, int height, int color, int
spc, int num, Icon icon[], char **text);
void CreateIconRow(int xo,int yo,int width,int height,int color,
int spc, int num, Icon icon[],char **text);
// WINDOW ROUTINES
void InitGraphics(void);
void SetWindow3D(int vp, int size);
void SetViewpoint(void);
void clearWindow(int vp);
void WorldToDevice(double xw, double yw, int *xpc, int *ypc);
void ScreenToWorld(int mx, int my, float *wx, float *wy);
void World2DToDevice(POINT3D pp,int *xd, int *yd);
POINTint World3DToDevice(POINT3D v1);
void GetGridPoint2D(GRID g, int mx,int my, float * wx, float * wy);
POINT3D GetPoint3D(int mx, int my);
// 3D DRAWING ROUTINES
void drawpoint3D(POINT3D *v1);
void drawline3D(POINT3D *v1, POINT3D *v2);
void DrawAxes(void);
void drawsphere (int WinNum, POINT3D pc,float R);
// VECTOR ROUTINES
POINT3D add(POINT3D *a,POINT3D *b);
POINT3D subtract(POINT3D *at,POINT3D *from);
float mag(POINT3D *v);
int equal(POINT3D *a, POINT3D *b);
POINT3D multiply(POINT3D *v,float f);
POINT3D divide(POINT3D *v,float d);
POINT3D cross(POINT3D *v1, POINT3D *v2);
// MISCELLANEOUS ROUTINES
float DegToRad(float deg);
void AllocateInputBox(void);
void EraseInputBox(void);
char * InputBox(char *s);
char* KeyInput(char* str,int text);
char* prompt (int x,int y);
int YesNoCMD(char *s);
void InfoBox(char *s);
// BLOB ROUTINES
float BlobFunc (POINT3D p);
int AllocateCubes (void);
void FreeCubes (void);
void SampleLevel (SAMPLE **level, int ix, POINT3D *vmin, POINT3D *vmax);
int CreateBlobs (void);
void CubeIntersect (int iy, int iz);
void FaceIntersect (SAMPLE *cube, int a, int b, int c, int d, PAIR3D *line, int *
numline);
void EdgeIntersect (POINT3D *v, SAMPLE *a, SAMPLE *b);
void DrawBlobs(BLOB b, int vp);
// MENU COMMANDS
void ExecCommand(int c, int mx, int my, int use_xy, int btnprss);
void CreateABlob(int mx, int my, int use_xy, int btn);
void SelectABlob(int mx, int my, int use_xy, int btn);
void CenterAView(int mx, int my, int use_xy, int btn);
void Zoom(int mx, int my, int use_xy, int btn);
void MoveABlob(int mx, int my, int use_xy, int btn, int copy);
void WriteToPolyray(void);
void WriteToPoV(void);
void DeleteBlob(int mx, int my, int use_xy, int btn);
void LoadAFile(char *str);
void SaveAFile(char *str);
void RedrawALL(void);
void SetStrength(int mx, int my, int use_xy, int btn);
void SetCamera(void);
void ResizeABlob(int mx, int my, int use_xy, int btn);
void drawgrid (int cw, GRID g);
//----------------
union REGS inregs; // mouse related
union REGS outregs; // mouse related
extern unsigned _stklen = 8000;
// Global Info For Drawing
POINT3D from, up, at; //viewing parameters
POINT3D a1, a2, a3; //used in transforming coordinates
int DeviceBottom, DeviceTop, //boundaries of viewing area
DeviceLeft, DeviceRight;
float a, b, c, d, DVal;
float angle; //viewing angle
float offset_x, offset_y, offset_z; //transform variables
int ViewPort; // Current Selected ViewPort
int BlobSel = 0; // selected blob
int BlobSelOld = 0;
int SaveRAW = 0; // RAW
WorldLimits World[3];
char FileName[80]; // current file loaded
FILE *RAWfptr; // for saving RAW data faster
float threshold = 0.6;
int bnum = 0; // number of blobs
#define MAXBLOB 500
BLOB blobs[MAXBLOB+1];
int LastCMD = -1; // last command select
void *BitMap;
GRID grid[3]; // grids for 3 views
int GridRowCol = 20; // divisions on grid
int GridStatus = 0; // show grid?
int SnapStatus = 0; // show grid/snap?
SAMPLE **level0 = NULL;
SAMPLE **level1 = NULL;
int x_steps = 30;
int y_steps = 30;
int z_steps = 30;
int hide_backface = 1; /* 0 = see through, 1 = front faces only */
#define IconNum 25
//---------------------------------------------------------------------
void main(void)
{
int i, mx, my, mxold = -1, myold = -1, status, status2, btn=0 ;
Icon icon[IconNum];
#define KLR LIGHTBLUE
icon[2] = CreateIcon(483, 3,72,15,KLR," Create");
icon[4] = CreateIcon(483, 21,72,15,KLR," Resize");
icon[3] = CreateIcon(483, 39,72,15,KLR," Move");
icon[24] = CreateIcon(483, 57,72,15,KLR," Copy");
icon[9] = CreateIcon(483, 75,72,15,KLR," Delete");
icon[13] = CreateIcon(483, 93,72,15,KLR," Density");
#undef KLR
#define KLR CYAN
icon[0] = CreateIcon(560, 3,72,15,KLR," Load");
icon[18] = CreateIcon(560, 21,72,15,KLR," New");
icon[1] = CreateIcon(560, 39,72,15,KLR," Save");
icon[5] = CreateIcon(560, 57,72,15,KLR," Povray");
icon[6] = CreateIcon(560, 75,72,15,KLR," Polyray");
icon[7] = CreateIcon(560, 93,72,15,KLR," RAW");
#undef KLR
#define KLR CYAN
icon[16] = CreateIcon(483, 129,72,15,KLR," Redraw");
icon[10] = CreateIcon(483, 147,72,15,KLR," Pan");
icon[23] = CreateIcon(483, 165,72,15,KLR," Origin");
icon[8] = CreateIcon(483, 183,72,15,KLR," Zoom");
#undef KLR
#define KLR LIGHTBLUE
icon[20] = CreateIcon(560, 129,72,15,KLR," Snap");
icon[21] = CreateIcon(560, 147,72,15,KLR," Grid");
icon[22] = CreateIcon(560, 165,72,15,KLR," Row/Col");
#undef KLR
#define KLR RED
icon[19] = CreateIcon(515, 288,100,15,KLR," Threshold");
icon[12] = CreateIcon(483, 306,72,15,KLR," Preview");
icon[17] = CreateIcon(560, 306,72,15,KLR," Detail");
icon[11] = CreateIcon(515, 324,100,15,KLR," Camera");
#undef KLR
icon[14] = CreateIcon(500, 450,72,15,7," Quit");
icon[15] = CreateIcon(580, 450,40,15,7," Who");
// FRONT DEFAULT VALUES
World[0].Hmin = -2;
World[0].Vmin = -2;
World[0].Hmax = 2;
World[0].Vmax = 2;
// SIDE DEFAULT VALUES
World[1].Hmin = -2;
World[1].Vmin = -2;
World[1].Hmax = 2;
World[1].Vmax = 2;
// TOP DEFAULT VALUES
World[2].Hmin = -2;
World[2].Vmin = -2;
World[2].Hmax = 2;
World[2].Vmax = 2;
// ISO DEFAULT VALUES
from.x = 1; from.y = 1; from.z = -2.5;
at.x = 0; at.y = 0; at.z = 0;
up.x = 0; up.y = 1; up.z = 0;
angle = DegToRad(45);
InitGraphics();
if (!IsMouse()) {
closegraph(); printf("MOUSE driver not installed!"); exit(1);
}
setcolor(7);
rectangle(0,0,getmaxy(),getmaxy());
line(1,240,getmaxy(),240);
line(240,1,240,getmaxy());
setcolor(15);
setfillstyle(1, 7);
bar3d(481,0,getmaxx(),getmaxy(),0,0);
for(i=0;i<IconNum;i++) DrawIcon(icon[i]);
setcolor(15);
setfillstyle(1, 15);
bar3d(530,260,610,275,0,0);
setcolor(0);
outtextxy(531, 262, "SNAP OFF");
outtextxy(490, 355, "Blob Sculptor 1.0a");
setcolor(WHITE);
outtextxy(491, 356, "Blob Sculptor 1.0a");
strcpy(FileName,"");
RedrawALL();
status = 0;
setcolor(WHITE);
MouseShow(1);
do {
do {MouseXY (&mx, &my);
if((mx != mxold) || (my != myold)) {
UpdateMousePos(mx,my,0);
mxold = mx;
myold = my;
}
btn = MouseClick();
}while(!btn);
for (i=0;i<IconNum;i++) {
status = IconCheck(icon[i],mx,my);
if (status) {
DrawIconHiLite(icon[i], DOWN);
if (LastCMD > -1) DrawIconHiLite(icon[LastCMD],UP);
if (i == 14) {
status = 14;
break;
}
else {
LastCMD = i;
ExecCommand(i, mx, my, 0, btn);
}
}
}
if (!status) { // If an icon command wasn't executed
status2 = WhereIsMouse(mx,my);
if ((status2 == FRONT_AREA) ||
(status2 == SIDE_AREA) ||
(status2 == TOP_AREA) ||
(status2 == ISO_AREA)) ExecCommand(LastCMD, mx, my, 1, btn);
}
if ((LastCMD == 0) ||
(LastCMD == 1) ||
(LastCMD == 5) ||
(LastCMD == 6) ||
(LastCMD == 7) ||
(LastCMD == 12) ||
((LastCMD > 13) && (LastCMD <= 22))) {
FULLSCREEN_VIEW
delay(50);
DrawIconHiLite(icon[LastCMD],UP);
LastCMD = -1;
}
}while(status != 14);
closegraph();
exit(1);
}
/////////////////////////////////////////////////////////////////////
void UpdateGridStatus(int vp)
{
grid[vp].rmin = World[vp].Vmin;
grid[vp].cmin = World[vp].Hmin;
grid[vp].rowstep = (fabs(World[vp].Vmin)+ fabs(World[vp].Vmax)) / (1.0 * GridRowCol);
grid[vp].colstep = (fabs(World[vp].Hmin)+ fabs(World[vp].Hmax)) / (1.0 * GridRowCol);
grid[vp].PlaneDist = 0.0;
grid[vp].rows = GridRowCol;
grid[vp].cols = GridRowCol;
switch(vp) {
case 0: grid[vp].PerpTo = 'Z';break;
case 1: grid[vp].PerpTo = 'X';break;
case 2: grid[vp].PerpTo = 'Y';break;
case 3: grid[vp].PerpTo = 'Z';break;
}
}
void CreateIconRow(int xo,int yo,int width,int height,int color,
int spc, int num, Icon icon[],char **text)
{
int i,x;
x = xo;
for(i=0;i<num;i++) {
icon[i] = CreateIcon(x,yo,width,height,color,text[i]);
x += width + spc;
}
}
int YesNoCMD(char *s)
{
char *str[2] = {" Yes"," No"};
Icon icon[2];
int i,xpos,ypos,status,choice = 0;
CreateIconRow(180,200,55,15,LIGHTGRAY,60,2,icon,str);
MouseShow(0);
FULLSCREEN_VIEW
setfillstyle(1,LIGHTGRAY);
bar3d(150,150,400,220,0,0);
for(i=0;i<2;i++) DrawIcon(icon[i]);
setcolor(0);
outtextxy(160,160,s);
MouseShow(1);
do {MouseXY(&xpos, &ypos); }while(!MouseClick());
for(i=0;i<2;i++) {
status = IconCheck(icon[i],xpos,ypos);
if (status) {
switch(i) {
case 0: choice = 1;break;
case 1: choice = 0;break;
}
}
}
return(choice);
}
void InfoBox(char *s)
{
int xpos,ypos;
MouseShow(0);
FULLSCREEN_VIEW
setfillstyle(1,LIGHTGRAY);
bar3d(100,100,120 + strlen(s) * textwidth("W") ,100 + 6 * textheight("W"),0,0);
setcolor(0);
outtextxy(110,110,s);
MouseShow(1);
do {MouseXY(&xpos, &ypos); }while(!MouseClick());
}
void ResizeABlob(int mx, int my, int use_xy, int btn)
{
int i, mxold=0, myold=0;
POINT3D p1, p2, v;
BLOB tmp, tmpold;
SelectABlob(mx, my, use_xy, btn);
if (BlobSel) {
tmp = blobs[BlobSel];
tmpold = tmp;
p1.x = tmp.x; p1.y = tmp.y; p1.z = tmp.z;
setcolor(WHITE);
MouseShow(0);
for(i=0;i<4;i++) {
SetWindow3D(i,0);
DrawBlobs(blobs[BlobSel],i);
}
MouseShow(1);
do {MouseXY (&mx, &my);
if((mx != mxold) || (my != myold)) {
UpdateMousePos(mx,my,0);
mxold = mx;
myold = my;
}
p2 = GetPoint3D(mx,my);
v = subtract(&p2, &p1);
tmp.radius = mag(&v)/sqrt(1.0 - sqrt(threshold/fabs(tmp.strength)));
MouseShow(0);
setwritemode(1);
setcolor(WHITE);
for(i=0;i<3;i++) {
SetWindow3D(i,0);
DrawBlobs(tmpold,i);
DrawBlobs(tmp,i);
}
setwritemode(0);
MouseShow(1);
tmpold = tmp;
btn = MouseClick();
}while(!btn);
if (btn == 1) blobs[BlobSel] = tmp;
RedrawALL();
}
}
void SetCamera(void)
{
int i,j,c,ok = 0,xpos,ypos;
char *str[11] = {" From X", " From Y", " From Z",
" To X", " To Y", " To Z",
" Up X", " Up Y", " Up Z",
" OK ", " Cancel "};
Icon Col[11];
char terms[9][80], s[80], s2[40];
FULLSCREEN_VIEW
MouseShow(0);
CreateIconColumn(75,100,60,15,LIGHTGRAY,5,11,Col,str);
for(i=9;i<11;i++) {
Col[i].x = Col[i-9].x + 300;
Col[i].y = Col[i-9].y;
}
sprintf(s2,"%g",from.x); strcpy(terms[0],s2);
sprintf(s2,"%g",from.y); strcpy(terms[1],s2);
sprintf(s2,"%g",from.z); strcpy(terms[2],s2);
sprintf(s2,"%g", at.x); strcpy(terms[3],s2);
sprintf(s2,"%g", at.y); strcpy(terms[4],s2);
sprintf(s2,"%g", at.z); strcpy(terms[5],s2);
sprintf(s2,"%g", up.x); strcpy(terms[6],s2);
sprintf(s2,"%g", up.y); strcpy(terms[7],s2);
sprintf(s2,"%g", up.z); strcpy(terms[8],s2);
setcolor(0);
setfillstyle(1,LIGHTGRAY);
bar3d(60,85,Col[9].x + 70,Col[8].y + 30,0,0);
for(i=0;i<11;i++) DrawIcon(Col[i]);
outtextxy((Col[9].x + 10)/2 + 60,88,"CAMERA");
MouseShow(1);
do {
MouseShow(0);
setcolor(LIGHTGRAY);
setfillstyle(1,LIGHTGRAY);
bar3d(Col[0].x+62,Col[0].y,Col[9].x - 2,Col[8].y + 15,0,0);
setcolor(0);
for(c=0;c<9;c++) outtextxy(Col[c].x + 70,Col[c].y + 3,terms[c]);
MouseShow(1);
do { MouseXY(&xpos, &ypos);
}while(!MouseClick());
for(i=0;i<11;i++) {
j = IconCheck(Col[i],xpos,ypos);
if (j) {
if ((i>=0) && (i<=8)) {
MouseShow(0);
strcpy(s,KeyInput(Col[i].str,NUMBER_INPUT));
MouseShow(1);
if (strlen(s)) strcpy(terms[i],s);
}
else {
if (i==9) ok = 1;
if (i==10) ok = -1;
}
}
}
}while(ok == 0);
if (ok == 1) {
from.x = atof(terms[0]); from.y = atof(terms[1]); from.z = atof(terms[2]);
at.x = atof(terms[3]); at.y = atof(terms[4]); at.z = atof(terms[5]);
up.x = atof(terms[6]); up.y = atof(terms[7]); up.z = atof(terms[8]);
}
RedrawALL();
}
void SetStrength(int mx, int my, int use_xy, int btn)
{
char str[80],pstr[80];
SelectABlob(mx,my,use_xy,btn);
FULLSCREEN_VIEW
if (BlobSel) {
sprintf(pstr,"Strength: [%g]",blobs[BlobSel].strength);
strcpy(str,KeyInput(pstr,NUMBER_INPUT));
if (strcmp(str,"")) blobs[BlobSel].strength = atof(str);
}
}
void RedrawALL(void)
{
int i,j;
FULLSCREEN_VIEW
MouseShow(0);
setcolor(7);
rectangle(0,0,getmaxy(),getmaxy());
line(1,240,getmaxy(),240);
line(240,1,240,getmaxy());
setcolor(WHITE);
for (i=0;i<4;i++) {
SetWindow3D(i,0);
clearviewport();
UpdateGridStatus(i); // must be updated ALWAYS!
if (GridStatus && (i < 3)) {
setcolor(LIGHTGRAY);
drawgrid(i,grid[i]);
}
DrawAxes();
setcolor(WHITE);
if (bnum) {
for(j=1;j<=bnum;j++) {
if (blobs[j].strength < 0) setcolor(LIGHTRED);
else setcolor(WHITE);
DrawBlobs(blobs[j],i);
}
}
}
setcolor(WHITE);
MouseShow(1);
}
void AllocateInputBox(void)
{
unsigned size;
size = imagesize(200,200,500,300);
if ((BitMap = (void *)malloc(size)) == NULL)
{
printf("Not enough memory to allocate buffer!\n");
exit(1);
}
MouseShow(0);
getimage(200,200,500,300,BitMap);
MouseShow(1);
}
void EraseInputBox(void)
{
MouseShow(0);
putimage(200,200,BitMap,COPY_PUT);
free(BitMap);
MouseShow(1);
}
char * InputBox(char *s)
{
static char ans[80];
MouseShow(0);
AllocateInputBox();
setfillstyle(1,LIGHTGRAY);
bar3d(200,200,500,300,0,0);
setcolor(15);
rectangle(200,200,500,300);
rectangle(205,300-2*textheight("W")-5,495,295);
setcolor(0);
outtextxy(205,205,s);
MouseShow(1);
strcpy(ans,prompt(207,300-2*textheight("W")-3));
MouseShow(0);
EraseInputBox();
MouseShow(1);
return(ans);
}
char* KeyInput(char* str,int text)
{
static char str1[80];
int i,error;
do
{
error = 0;
strcpy(str1,InputBox(str));
if (text==0)
{
for (i=0;i<strlen(str1);i++)
if ((!isdigit(str1[i])) && (str1[i] != '.')
&& (toupper(str1[i]) != 'E') && (str1[i] != '-'))
error = 1;
}
else {
for (i=0;i<strlen(str1);i++)
if (str1[i] == ' ') error = 1;
}
}while(error);
return (str1);
}
char* prompt (int x,int y)
{
char KeyChar,key[2];
static char word[80];
int j, erase, stop,TW = textwidth("W"),TH = textheight("W")+1;
j = 0;
setcolor(0);
erase = stop = 0;
key[1] = '\0';
do
{
KeyChar = getch();
key[0] = KeyChar;
if (KeyChar == 13) stop = 1;
if ((KeyChar == 8) && (j > 0)) erase = 1;
if (KeyChar == 0) {
KeyChar = getch();
if (((KeyChar == 75) || (KeyChar == 83)) && (j > 0)) erase = 1;
}
if (stop) word[j] = '\0';
else
if (erase) {
if (j) {
j --;
MouseShow(0);
bar(x+TW*j,y,x+TW*(j+2),y+TH);
outtextxy(x+TW*j,y,"_");
MouseShow(1);
}
erase = 0;
}
else {
if(j<34) {
MouseShow(0);
bar(x+TW*j,y,x+TW*(j+2),y+TH);
outtextxy(x+TW*j,y,key);
outtextxy(x+TW*(j+1),y,"_");
MouseShow(1);
word[j] = key[0];
j++;
}
}
}while(!stop);
return(word);
}
void LoadAFile(char *str)
{
FILE *fptr;
float x,y,z,r,s;
if ( (fptr = fopen(str,"r")) == NULL) {
InfoBox("Can't load the file!");
RedrawALL();
}
else {
bnum = 0;
fscanf(fptr,"%f",&threshold);
while (!feof(fptr)) {
if ((fscanf(fptr,"%f",&x) > 0) &&
(fscanf(fptr,"%f",&y) > 0) &&
(fscanf(fptr,"%f",&z) > 0) &&
(fscanf(fptr,"%f",&s) > 0) &&
(fscanf(fptr,"%f",&r) > 0) &&
(r > TOL) &&
(bnum < MAXBLOB)) {
bnum++;
blobs[bnum].x = x;
blobs[bnum].y = y;
blobs[bnum].z = z;
blobs[bnum].radius = r;
blobs[bnum].strength = s;
}
}
fclose(fptr);
strcpy(FileName,str);
}
}
void SaveAFile(char *str)
{
FILE *fptr;
int i=1;
char s[40];
sprintf(s,"Overwrite < %s > ?",str);
if ((fptr = fopen(str,"r")) != NULL) i = YesNoCMD(s);
fclose(fptr);
if (i) {
if ((fptr = fopen(str,"w+t")) == NULL) {
InfoBox("Can't open the file for output!");
RedrawALL();
}
else {
if(bnum) {
MouseShow(0);
fprintf(fptr,"%g\n",threshold);
for(i=1;i<=bnum;i++)
if (blobs[i].radius > TOL)
fprintf(fptr,"%g %g %g %g %g\n",blobs[i].x,blobs[i].y,blobs[i].z,
blobs[i].strength,blobs[i].radius);
fclose(fptr);
MouseShow(1);
}
}
}
RedrawALL();
}
void DeleteBlob(int mx, int my, int use_xy, int btn)
{
int i;
SelectABlob(mx, my, use_xy, btn);
if (BlobSel) {
if (YesNoCMD("Delete Blob?")) {
if (BlobSel && bnum ) {
if (BlobSel == bnum)
bnum--;
else {
for(i = BlobSel; i<bnum; i++) blobs[i] = blobs[i+1];
bnum--;
}
}
}
RedrawALL();
}
}
void WriteToPoV(void)
{
FILE *fptr;
char str[80];
int i;
if (bnum) {
MouseShow(0);
strcpy(str,KeyInput("Save As < BLOB.POV >",TEXT_INPUT));
if (strlen(str) == 0) strcpy(str,"BLOB.POV");
MouseShow(1);
fptr = fopen(str, "w+");
fprintf(fptr,"#include \"colors.inc\"\n");
fprintf(fptr,"#include \"textures.inc\"\n");
fprintf(fptr,"#include \"shapes.inc\"\n\n");
fprintf(fptr,"\ncamera {\n");
fprintf(fptr," location <%g, %g, %g>\n",from.x,from.y,from.z);
fprintf(fptr," look_at <%g, %g, %g>\n",at.x,at.y,at.z);
fprintf(fptr," up <%g, %g, %g>\n",up.x,up.y,up.z);
fprintf(fptr,"}\n\n\n");
fprintf(fptr,"light_source{< %g , %g , %g > color White }\n\n",
from.x,from.y,from.z);
fprintf(fptr,"blob {\n");
fprintf(fptr," threshold %g\n",threshold);
for(i=1;i<=bnum;i++) {
if (blobs[i].radius < TOL) fprintf(fptr,"//");
fprintf(fptr, " component %g, %g, <%g, %g, %g>\n", blobs[i].strength,
blobs[i].radius,
blobs[i].x,
blobs[i].y,
blobs[i].z);
}
fprintf(fptr, "\n texture {Gold_Metal}\n}\n");
fclose(fptr);
}
}
void WriteToPolyray(void)
{
FILE *fptr;
char str[80];
int i;
if (bnum) {
MouseShow(0);
strcpy(str,KeyInput("Save As < BLOB.PI >",TEXT_INPUT));
if (strlen(str) == 0) strcpy(str,"BLOB.PI");
MouseShow(1);
fptr = fopen(str, "w+");
fprintf(fptr,"include \"colors.inc\"\n");
fprintf(fptr,"include \"texture.inc\"\n");
fprintf(fptr,"\nviewpoint {\n");
fprintf(fptr," from <%g, %g, %g>\n",from.x,from.y,from.z);
fprintf(fptr," at <%g, %g, %g>\n",at.x,at.y,at.z);
fprintf(fptr," up <%g, %g, %g>\n",up.x,up.y,up.z);
fprintf(fptr," angle 45\n resolution 200,200\n aspect 1.0\n}\n\n");
fprintf(fptr,"light <%g, %g, %g>\n\n",from.x,from.y,from.z);
fprintf(fptr,"object {\n");
fprintf(fptr," blob %g:\n",threshold);
for(i=1;i<=bnum;i++) {
if (blobs[i].radius < TOL) fprintf(fptr,"//");
fprintf(fptr, " sphere <%g, %g, %g>, %g, %g", blobs[i].x,
blobs[i].y,
blobs[i].z,
blobs[i].strength,
blobs[i].radius);
if (i < bnum) fprintf(fptr,",\n");
else fprintf(fptr,"\n");
}
fprintf(fptr, "\n shiny_yellow \n}\n");
fclose(fptr);
}
}
void Zoom(int mx, int my, int use_xy, int btn)
{
int i, mxold=0, myold=0, pos;
float d;
if(!use_xy) {
do {MouseXY (&mx, &my);
if((mx != mxold) || (my != myold)) {
UpdateMousePos(mx,my,0);
mxold = mx;
myold = my;
}
btn = 0;
btn = MouseClick();
}while(!btn);
}
if (btn == 1) d = 0.5;
else d = 2.0;
pos = WhereIsMouse(mx,my);
switch(pos) {
case FRONT_AREA: //Y X
World[0].Hmin *= d;
World[0].Vmin *= d;
World[0].Hmax *= d;
World[0].Vmax *= d;
break;
case SIDE_AREA: // Y Z
World[1].Hmin *= d;
World[1].Vmin *= d;
World[1].Hmax *= d;
World[1].Vmax *= d;
break;
case TOP_AREA: // Z X
World[2].Hmin *= d;
World[2].Vmin *= d;
World[2].Hmax *= d;
World[2].Vmax *= d;
break;
case ISO_AREA: // ISO
from.x *= d;
from.y *= d;
from.z *= d;
break;
}
if (pos != MENU_AREA) {
MouseShow(0);
SetWindow3D(pos,0);
clearviewport();
UpdateGridStatus(pos);
if ((pos < 3) && GridStatus) {
setcolor(LIGHTGRAY);
drawgrid(1,grid[pos]);
}
DrawAxes();
for(i=1;i<=bnum;i++) {
if (blobs[i].strength < 0) setcolor(LIGHTRED);
else setcolor(WHITE);
DrawBlobs(blobs[i],pos);
}
MouseShow(1);
}
setcolor(WHITE);
}
void CenterAView(int mx, int my, int use_xy, int btn)
{
int i, mxold=0, myold=0, pos;
POINT3D p0, p1;
btn++; // quiet the compiler!
if(!use_xy) {
do {MouseXY (&mx, &my);
if((mx != mxold) || (my != myold)) {
UpdateMousePos(mx,my,0);
mxold = mx;
myold = my;
}
}while(!MouseClick());
}
p1 = GetPoint3D(mx,my);
pos = WhereIsMouse(mx,my);
switch(pos) {
case FRONT_AREA: //Y X
p0.x = (World[0].Hmin + World[0].Hmax) / 2.0;
p0.y = (World[0].Vmin + World[0].Vmax) / 2.0;
p0.x = p1.x - p0.x;
p0.y = p1.y - p0.y;
World[0].Hmin += p0.x;
World[0].Vmin += p0.y;
World[0].Hmax += p0.x;
World[0].Vmax += p0.y;
break;
case SIDE_AREA: // Y Z
p0.z = (World[1].Hmin + World[1].Hmax) / 2.0;
p0.y = (World[1].Vmin + World[1].Vmax) / 2.0;
p0.z = p1.z - p0.z;
p0.y = p1.y - p0.y;
World[1].Hmin += p0.z;
World[1].Vmin += p0.y;
World[1].Hmax += p0.z;
World[1].Vmax += p0.y;
break;
case TOP_AREA: // Z X
p0.x = (World[2].Hmin + World[2].Hmax) / 2.0;
p0.z = (World[2].Vmin + World[2].Vmax) / 2.0;
p0.x = p1.x - p0.x;
p0.z = p1.z - p0.z;
World[2].Hmin += p0.x;
World[2].Vmin += p0.z;
World[2].Hmax += p0.x;
World[2].Vmax += p0.z;
break;
}
if( (pos != MENU_AREA)) {
MouseShow(0);
SetWindow3D(pos,0);
UpdateGridStatus(pos);
clearviewport();
if ((pos < 3) && GridStatus) {
setcolor(LIGHTGRAY);
drawgrid(1,grid[pos]);
}
DrawAxes();
for(i=1;i<=bnum;i++) {
if (blobs[i].strength < 0 ) setcolor(LIGHTRED);
else setcolor(WHITE);
DrawBlobs(blobs[i],pos);
}
MouseShow(1);
}
setcolor(WHITE);
}
void CreateABlob(int mx, int my, int use_xy, int btn)
{
int i, mxold=0, myold=0, FLAG = 0;
POINT3D p1, p2, v;
BLOB tmp, tmpold;
if (bnum <MAXBLOB) {
setcolor(WHITE);
if(!use_xy) {
do {MouseXY (&mx, &my);
if((mx != mxold) || (my != myold)) {
UpdateMousePos(mx,my,0);
mxold = mx;
myold = my;
}
btn = MouseClick();
}while(!btn);
}
if (btn == 1) {
p1 = GetPoint3D(mx,my);
do {MouseXY (&mx, &my);
if((mx != mxold) || (my != myold)) {
UpdateMousePos(mx,my,0);
mxold = mx;
myold = my;
}
p2 = GetPoint3D(mx,my);
tmp.x = p1.x;
tmp.y = p1.y;
tmp.z = p1.z;
v = subtract(&p2, &p1);
tmp.strength = 1.0;
tmp.radius = mag(&v)/sqrt(1.0 - sqrt(threshold/fabs(tmp.strength)));
MouseShow(0);
setwritemode(1);
for(i=0;i<3;i++) { SetWindow3D(i,0); DrawBlobs(tmp,i); }
setwritemode(0);
MouseShow(1);
if (!FLAG) FLAG = 1;
else {
MouseShow(0);
setwritemode(1);
for(i=0;i<3;i++) { SetWindow3D(i,0); DrawBlobs(tmpold,i); }
setwritemode(0);
MouseShow(1);
}
tmpold = tmp;
btn = MouseClick();
}while(!btn);
if (btn == 1) {
bnum++;
blobs[bnum] = tmp;
}
RedrawALL();
} //if LMB was pressed do not create the center point!
}// if bnum < MAXBLOB
}
void MoveABlob(int mx, int my, int use_xy, int btn, int copy)
{
int i, mxold=0, myold=0,pos;
POINT3D p2;
BLOB tmp, tmpold;
SelectABlob(mx,my,use_xy,btn);
if (BlobSel) {
tmp = blobs[BlobSel];
tmpold = tmp;
do {MouseXY (&mx, &my);}while(!MouseClick());
setcolor(WHITE);
MouseShow(0);
for(i=0;i<4;i++) {
SetWindow3D(i,0);
DrawBlobs(blobs[BlobSel],i);
}
MouseShow(1);
do {MouseXY (&mx, &my);
if((mx != mxold) || (my != myold)) {
UpdateMousePos(mx,my,0);
mxold = mx;
myold = my;
}
p2 = GetPoint3D(mx,my);
pos = WhereIsMouse(mx,my);
switch(pos) {
case FRONT_AREA: tmp.x = p2.x; tmp.y = p2.y; break;
case SIDE_AREA: tmp.y = p2.y; tmp.z = p2.z; break;
case TOP_AREA: tmp.x = p2.x; tmp.z = p2.z; break;
}
MouseShow(0);
setwritemode(1);
setcolor(WHITE);
for(i=0;i<3;i++) {
SetWindow3D(i,0);
DrawBlobs(tmpold,i);
DrawBlobs(tmp,i);
}
setwritemode(0);
MouseShow(1);
tmpold = tmp;
btn = MouseClick();
}while(!btn);
if (btn == 1) {
if (!copy) blobs[BlobSel] = tmp;
else {
if (bnum < MAXBLOB) {bnum++; blobs[bnum] = tmp;}
}
}
RedrawALL();
}
}
void SelectABlob(int mx, int my, int use_xy, int btn)
{
int pos, i, mxold=0, myold=0;
float dist, dist2, rr;
POINT3D p1;
setcolor(WHITE);
if(!use_xy) {
do {MouseXY (&mx, &my);
btn = 0;
if((mx != mxold) || (my != myold)) {
UpdateMousePos(mx,my,0);
mxold = mx;
myold = my;
}
btn = MouseClick();
}while(!btn);
}
if (btn==1) {
p1 = GetPoint3D(mx,my);
pos = WhereIsMouse(mx,my);
dist = 3e30;
BlobSel = 0;
for(i=1;i<=bnum;i++) {
switch(pos) {
case FRONT_AREA:
dist2 = (blobs[i].x - p1.x)*(blobs[i].x - p1.x) +
(blobs[i].y - p1.y)*(blobs[i].y - p1.y);
break;
case SIDE_AREA:
dist2 = (blobs[i].z - p1.z)*(blobs[i].z - p1.z) +
(blobs[i].y - p1.y)*(blobs[i].y - p1.y);
break;
case TOP_AREA:
dist2 = (blobs[i].x - p1.x)*(blobs[i].x - p1.x) +
(blobs[i].z - p1.z)*(blobs[i].z - p1.z);
break;
default : dist2 = 3e30; break; //in case you select outside!
}
rr = blobs[i].radius * sqrt(1.0 - sqrt(threshold/fabs(blobs[i].strength)));
dist2 -= rr * rr;
dist2 = fabs(dist2);
if (dist2 < dist) {
dist = dist2;
BlobSel = i;
}
}
if (BlobSel) {
MouseShow(0);
for(i=0;i<4;i++) {
SetWindow3D(i,0);
setcolor(YELLOW);
DrawBlobs(blobs[BlobSel],i);
if(BlobSelOld && (BlobSelOld != BlobSel) && (BlobSelOld <= bnum)) {
setcolor(WHITE);
DrawBlobs(blobs[BlobSelOld],i);
}
}
setcolor(WHITE);
MouseShow(1);
BlobSelOld = BlobSel;
}
}
}
void DrawBlobs(BLOB b, int vp)
{
POINT3D p;
p.x = b.x;
p.y = b.y;
p.z = b.z;
drawsphere (vp, p, b.radius * sqrt(1.0 - sqrt(threshold/fabs(b.strength))));
}
void ExecCommand(int c, int mx, int my, int use_xy, int btnprss)
{
FILE *fptr;
char tfile[80], s[80];
int i;
switch(c) {
//[0] " Load"
case 0: strcpy(tfile,KeyInput("Load File:",TEXT_INPUT));
LoadAFile(tfile);
RedrawALL();
break;
//[1] " Save "
case 1: MouseShow(0);
sprintf(tfile,"Save As < %s >",FileName);
strcpy(tfile,KeyInput(tfile,TEXT_INPUT));
if (strlen(tfile) == 0) strcpy(tfile,FileName);
MouseShow(1);
SaveAFile(tfile);
break;
//[2] " Create"
case 2: CreateABlob(mx, my, use_xy,btnprss); break;
//[3] " Move"
case 3: MoveABlob(mx, my, use_xy,btnprss,0); break;
//[4] " Resize"
case 4: if (bnum) ResizeABlob(mx, my, use_xy,btnprss) ;break;
//[5] " Povray"
case 5: MouseShow(0);
WriteToPoV();
MouseShow(1);
break;
//[6] " Polyray"
case 6: MouseShow(0);
WriteToPolyray();
MouseShow(1);
break;
//[7] " RAW"
case 7: SaveRAW = 1;
hide_backface = 0;
i = 1;
MouseShow(0);
strcpy(tfile,KeyInput("Save As < BLOB.RAW >",TEXT_INPUT));
if (strlen(tfile) == 0) strcpy(tfile,"BLOB.RAW");
MouseShow(1);
sprintf(s,"Overwrite < %s > ?",tfile);
if ((fptr = fopen(tfile,"r")) != NULL) {
i = YesNoCMD(s);
RedrawALL();
}
fclose(fptr);
if (i) {
fptr = fopen(tfile, "w+"); // open and close to clean up
fclose(fptr); // any previous data
setcolor(WHITE);
SetWindow3D(ISO_ID, 0);
MouseShow(0);
RAWfptr = fopen(tfile, "a+");
CreateBlobs();
fclose(RAWfptr);
MouseShow(1);
}
SaveRAW = 0;
hide_backface = 1;
break;
//[8] " Zoom"
case 8: Zoom(mx, my, use_xy,btnprss); break;
//[9] " Delete"
case 9: if (bnum) DeleteBlob(mx, my, use_xy,btnprss); break;
//[10] " Center"
case 10: CenterAView(mx, my, use_xy,btnprss); break;
//[11] " Camera"
case 11: SetCamera();
break;
//[12] " Preview"
case 12: if(bnum) {
setcolor(WHITE);
SetWindow3D(ISO_ID, 0);
MouseShow(0);
CreateBlobs();
MouseShow(1);
}
break;
//[13] " Strength"
case 13: if (bnum) SetStrength(mx, my, use_xy,btnprss);
break;
//[14] " Quit"
case 14: break;
//[15] " Who"
case 15:InfoBox("By Alfonso Hermida/Steve Anger 2/94");
RedrawALL();
break;
//[16] " Redraw"
case 16: RedrawALL(); break;
//[17] " Detail"
case 17: FULLSCREEN_VIEW
sprintf(tfile,"Detail Level <20 - 50> [%d]",x_steps);
strcpy(tfile,KeyInput(tfile,NUMBER_INPUT));
if (atoi(tfile) >= 20 && atoi(tfile) <= 50)
x_steps = y_steps = z_steps = atoi(tfile);
break;
//[18] " New"
case 18: if(YesNoCMD("Delete Database?")){
bnum =0;
strcpy(FileName,"");
}
RedrawALL();
break;
//[19] " Threshold"
case 19: FULLSCREEN_VIEW
sprintf(tfile,"Threshold Level (>0) [%g]",threshold);
strcpy(tfile,KeyInput(tfile,NUMBER_INPUT));
if (strlen (tfile) && atof(tfile) >= 0) threshold = atof(tfile);
break;
//[20] " Snap"
case 20: FULLSCREEN_VIEW
setcolor(15);
setfillstyle(1,WHITE);
bar3d(530,260,610,275,0,0);
setcolor(0);
if (SnapStatus) {
SnapStatus = 0;
outtextxy(531, 262, "SNAP OFF");
}
else {
SnapStatus = 1;
outtextxy(531, 262, "SNAP ON");
}
setcolor(WHITE);
break;
//[21] " Grid"
case 21: if (GridStatus) GridStatus = 0;
else GridStatus = 1;
RedrawALL();
break;
//[22] "Row/Col"
case 22: FULLSCREEN_VIEW
sprintf(tfile,"Grid Rows/Cols (>3) [%d]",GridRowCol);
strcpy(tfile,KeyInput(tfile,NUMBER_INPUT));
if (strlen (tfile) && atoi(tfile) >= 3) {
GridRowCol = atoi(tfile);
RedrawALL();
}
break;
//[23] " Origin"
case 23: do {MouseXY (&mx, &my);}while(!MouseClick());
i = WhereIsMouse(mx,my);
if (i >= 0 && i <= 2) {
World[i].Hmin = -2;
World[i].Vmin = -2;
World[i].Hmax = 2;
World[i].Vmax = 2;
RedrawALL();
}
break;
//[24] " Copy"
case 24: MoveABlob(mx, my, use_xy,btnprss,1); break;
}
}
void DrawIconHiLite(Icon ic, int UpDown)
{
MouseShow(0);
if(UpDown == DOWN) {
setcolor(15);
rectangle(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+ic.height-1);
setcolor(0);
line(ic.x,ic.y,ic.x+ic.width,ic.y);
line(ic.x,ic.y,ic.x,ic.y+ic.height);
line(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+1);
line(ic.x+1,ic.y+1,ic.x+1,ic.y+ic.height-1);
}
else {
setcolor(0);
rectangle(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+ic.height-1);
setcolor(15);
line(ic.x,ic.y,ic.x+ic.width,ic.y);
line(ic.x,ic.y,ic.x,ic.y+ic.height);
line(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+1);
line(ic.x+1,ic.y+1,ic.x+1,ic.y+ic.height-1);
}
MouseShow(1);
setcolor(WHITE);
}
POINT3D GetPoint3D(int mx, int my)
{
POINT3D temp;
float wx, wy;
int k;
k = WhereIsMouse(mx, my);
SetWindow3D(WhereIsMouse(mx,my),0);
switch(k) {
case FRONT_AREA : mx = mx - 1 ; my = my - 241; break;
case SIDE_AREA : mx = mx - 241; my = my - 241; break;
case TOP_AREA : mx = mx - 1 ; my = my - 1; break;
case ISO_AREA : mx = mx - 241; my = my - 1; break;
}
if (!SnapStatus)
ScreenToWorld(mx, my, &wx, &wy);
else
if (k < 3) GetGridPoint2D(grid[k],mx, my, &wx, &wy);
if (fabs(wx) < TOL) wx = 0.0;
if (fabs(wy) < TOL) wy = 0.0;
switch(k) {
case FRONT_AREA : temp.x = wx; temp.y = wy; temp.z = 0.0; break;
case SIDE_AREA : temp.x = 0.0; temp.y = wy; temp.z = wx; break;
case TOP_AREA : temp.x = wx; temp.y = 0.0; temp.z = wy; break;
case ISO_AREA : temp.x = wx; temp.y = wy; temp.z = 0.0; break;
}
return (temp);
}
void GetGridPoint2D(GRID g, int mx,int my, float * wx, float * wy)
{
int nx,ny;
ScreenToWorld(mx,my,wx,wy);
nx = (*wx - g.cmin) / (float)g.colstep + .5;
ny = (*wy - g.rmin) / (float)g.rowstep + .5;
*wx = g.cmin + nx * g.colstep;
*wy = g.rmin + ny * g.rowstep;
}
void drawgrid (int cw, GRID g)
{
int j;
float rmax,cmax;
POINT3D p1,p2;
cw++;
setlinestyle(DOTTED_LINE,1,NORM_WIDTH);
rmax = g.rmin+g.rowstep*(g.rows);
cmax = g.cmin+g.colstep*(g.cols);
// case = X _|_ X axis
// Y _|_ Y axis
// Z _|_ Z axis
switch(toupper(g.PerpTo))
{
case 'X':
for (j=0;j<g.cols+1;j++)
{
p1.x = g.PlaneDist;
p1.y = rmax;
p1.z = g.cmin+j*g.colstep;
p2.x = g.PlaneDist;
p2.y = g.rmin;
p2.z = g.cmin+j*g.colstep;
drawline3D(&p1,&p2);
}
for (j=0;j<g.rows+1;j++)
{
p1.x = g.PlaneDist;
p1.y = g.rmin+j*g.rowstep;
p1.z = cmax;
p2.x = g.PlaneDist;
p2.y = g.rmin+j*g.rowstep;
p2.z = g.cmin;
drawline3D(&p1,&p2);
}
break;
case 'Y':
for (j=0;j<g.cols+1;j++)
{
p1.z = rmax;
p1.y = g.PlaneDist;
p1.x = g.cmin+j*g.colstep;
p2.z = g.rmin;
p2.y = g.PlaneDist;
p2.x = g.cmin+j*g.colstep;
drawline3D(&p1,&p2);
}
for (j=0;j<g.rows+1;j++)
{
p1.z = g.rmin+j*g.rowstep;
p1.y = g.PlaneDist;
p1.x = g.cmin;
p2.z = g.rmin+j*g.rowstep;
p2.y = g.PlaneDist;
p2.x = cmax;
drawline3D(&p1,&p2);
}
break;
case 'Z':
for (j=0;j<g.cols+1;j++)
{
p1.x = g.cmin+j*g.colstep;
p1.y = rmax;
p1.z = g.PlaneDist;
p2.x = g.cmin+j*g.colstep;
p2.y = g.rmin,
p2.z = g.PlaneDist;
drawline3D(&p1,&p2);
}
for (j=0;j<g.rows+1;j++)
{
p1.x = g.cmin;
p1.y = g.rmin+j*g.rowstep;
p1.z = g.PlaneDist;
p2.x = cmax;
p2.y = g.rmin+j*g.rowstep;
p2.z = g.PlaneDist;
drawline3D(&p1,&p2);
}
break;
}
setlinestyle(SOLID_LINE,1,NORM_WIDTH);
}
void UpdateMousePos(int xpos,int ypos,int status)
{
int k;
float wx,wy;
char s[80], vpl[5];
strcpy(vpl,"");
k = WhereIsMouse(xpos, ypos);
switch(k) {
case FRONT_AREA : SetWindow3D(FRONT_ID,0);
xpos = xpos - 1; ypos = ypos - 241;
strcpy(vpl,"F");
break;
case SIDE_AREA : SetWindow3D(SIDE_ID,0);
xpos = xpos - 241; ypos = ypos - 241;
strcpy(vpl,"S");
break;
case TOP_AREA : SetWindow3D(TOP_ID,0);
xpos = xpos - 1; ypos = ypos - 1;
strcpy(vpl,"T");
break;
case ISO_AREA : SetWindow3D(ISO_ID,0);
xpos = xpos - 241; ypos = ypos - 1;
strcpy(vpl,"Iso");
break;
default: SetWindow3D(FRONT_ID,0);
xpos = xpos - 1; ypos = ypos - 241;
strcpy(vpl,"M");
break;
}
FULLSCREEN_VIEW
status++; // keep the compiler quiet!
if (!SnapStatus)
ScreenToWorld(xpos, xpos, &wx, &wy);
else
if (k < 3)
GetGridPoint2D(grid[k],xpos, ypos, &wx, &wy);
if (fabs(wx) < TOL) wx = 0.0;
if (fabs(wy) < TOL) wy = 0.0;
setcolor(15);
setfillstyle(1,WHITE);
bar3d(490,218,getmaxx(),218+15,0,0);
bar3d(490,218+15+5,getmaxx(),218+15+15+5,0,0);
bar3d(490,260,515,275,0,0);
setcolor(0);
if (k < 3) {
sprintf(s,"%g",wx);
outtextxy(490+2,218+2,s);
sprintf(s,"%g",wy);
outtextxy(490+2,218+15+5+2,s);
}
outtextxy(491, 262,vpl);
setcolor(WHITE);
}
int WhereIsMouse(int x, int y)
{
// For VGA only
if ((x > 1) && (x < 239) && (y > 241) && (y < 478)) return FRONT_AREA;
if ((x > 241) && (x < 478) && (y > 241) && (y < 478)) return SIDE_AREA;
if ((x > 1) && (x < 239) && (y > 1) && (y < 239)) return TOP_AREA;
if ((x > 241) && (x < 478) && (y > 1) && (y < 239)) return ISO_AREA;
return MENU_AREA;
}
void clearWindow(int vp)
{
switch(vp) {
case 0: FRONT_VIEW break;
case 1: SIDE_VIEW break;
case 2: TOP_VIEW break;
case 3: ISO_VIEW break;
}
MouseShow(0);
clearviewport();
MouseShow(1);
}
void SetWindow3D(int vp, int size)
{
ViewPort = vp;
if (!size) {
DeviceLeft = 1;
DeviceTop = 1;
DeviceRight = 238;
DeviceBottom = 238;
}
else {
DeviceLeft = 1;
DeviceTop = 1;
DeviceRight = getmaxy()-1;
DeviceBottom = getmaxy()-1;
}
a = (DeviceRight-DeviceLeft)/2.0;
b = DeviceLeft + a;
c = (DeviceTop-DeviceBottom)/2.0;
d = DeviceBottom + c;
SetViewpoint();
if (!size) {
switch(vp) {
case 0: FRONT_VIEW break;
case 1: SIDE_VIEW break;
case 2: TOP_VIEW break;
case 3: ISO_VIEW break;
}
}
else setviewport(1,1,getmaxy()-1,getmaxy()-1,1);
}
void DrawAxes(void)
{
POINT3D v1, v2;
setlinestyle(SOLID_LINE,1,THICK_WIDTH);
v1.x = 0.0; v1.y = 0.0; v1.z = 0.0;
setcolor(RED);
v2.x = 1.0; v2.y = 0.0; v2.z = 0.0;
drawline3D(&v1, &v2);
setcolor(GREEN);
v2.x = 0.0; v2.y = 1.0; v2.z = 0.0;
drawline3D(&v1, &v2);
setcolor(BLUE);
v2.x = 0.0; v2.y = 0.0; v2.z = 1.0;
drawline3D(&v1, &v2);
setcolor(WHITE);
setlinestyle(SOLID_LINE,1,NORM_WIDTH);
}
float DegToRad(float deg) {
return(deg * .017453293);
}
float RadToDeg(float rad) {
return(rad * 57.29577951);
}
void InitGraphics(void)
{
int gdriver = VGA, gmode = VGAHI, errorcode;
initgraph(&gdriver, &gmode, "");
errorcode = graphresult();
if (errorcode != grOk) /* an error occurred */
{
printf("Graphics error: %s\n", grapherrormsg(errorcode));
printf("Press any key to halt:");
getch();
exit(1); /* terminate with an error code */
}
setviewport(0,0,getmaxx(),getmaxy(),1); /* sets viewport with line clipping */
}
void WorldToDevice(double xw, double yw, int *xpc, int *ypc)
{
*xpc = (int)(a * xw + b);
*ypc = (int)(c * yw + d);
}
void ScreenToWorld(int mx, int my, float *wx, float *wy)
{
int v;
v = ViewPort;
if (ViewPort == 3) {
*wx = (float)(mx - b)/a;
*wy = (float)(my - d)/c;
}
else {
*wx = ((1 - mx) * (World[v].Hmin-World[v].Hmax))/(float)(238-1) + World[v].Hmin ;
*wy = ((1 - my) * (World[v].Vmax-World[v].Vmin))/(float)(238-1) + World[v].Vmax ;
}
}
POINT3D add(POINT3D *a,POINT3D *b)
{
POINT3D t;
t.x = a->x + b->x;
t.y = a->y + b->y;
t.z = a->z + b->z;
return(t);
}
POINT3D subtract(POINT3D *at,POINT3D *from)
{
POINT3D t;
t.x = at->x - from->x;
t.y = at->y - from->y;
t.z = at->z - from->z;
return(t);
}
float mag(POINT3D *v)
{
return sqrt(v->x * v->x + v->y * v->y + v->z * v->z);
}
int equal(POINT3D *a, POINT3D *b)
{
return (a->x == b->x && a->y == b->y && a->z == b->z);
}
POINT3D multiply(POINT3D *v,float f)
{
POINT3D t;
t.x = v->x * f;
t.y = v->y * f;
t.z = v->z * f;
return(t);
}
POINT3D divide(POINT3D *v,float d)
{
POINT3D t;
if (d == 0.0) {
d = TOL;
InfoBox("Error in DIVIDE function! Contact the authors. Save data!");
}
t.x = v->x / d;
t.y = v->y / d;
t.z = v->z / d;
return(t);
}
POINT3D cross(POINT3D *v1, POINT3D *v2)
{
POINT3D t;
t.x = v1->y * v2->z - v2->y * v1->z;
t.y = v1->z * v2->x - v2->z * v1->x;
t.z = v1->x * v2->y - v2->x * v1->y;
return(t);
}
void SetViewpoint(void)
{
POINT3D temp,temp2;
DVal = 1.0/tan(angle/2.0);
temp2 = subtract(&at, &from);
a3 = divide(&temp2, mag(&temp2));
temp = cross(&up, &temp2);
a1 = divide(&temp, mag(&temp));
temp = cross(&a3, &a1);
a2 = divide(&temp, mag(&temp));
offset_x = -a1.x * from.x - a1.y * from.y - a1.z * from.z;
offset_y = -a2.x * from.x - a2.y * from.y - a2.z * from.z;
offset_z = -a3.x * from.x - a3.y * from.y - a3.z * from.z;
}
void World2DToDevice(POINT3D pp,int *xd, int *yd)
{
int c;
POINT3D p;
c = ViewPort;
switch(c) {
case 0: p.x = pp.x; p.y = pp.y; break;
case 1: p.x = pp.z; p.y = pp.y; break;
case 2: p.x = pp.x; p.y = pp.z; break;
}
*xd = (World[c].Hmin-p.x)*(238-1)/(World[c].Hmin-World[c].Hmax) + 1.5;
*yd = (World[c].Vmax-p.y)*(238-1)/(World[c].Vmax-World[c].Vmin) + 1.5;
}
void drawline3D(POINT3D *v1, POINT3D *v2)
{
float x1, y1, z1, x2, y2, z2;
int xpc1,ypc1,xpc2,ypc2;
if (ViewPort ==3) {
x1 = (v1->x * a1.x + a1.y * v1->y + a1.z * v1->z + offset_x)*DVal;
y1 = (v1->x * a2.x + a2.y * v1->y + a2.z * v1->z + offset_y)*DVal;
z1 = v1->x * a3.x + a3.y * v1->y + a3.z * v1->z + offset_z;
x2 = (v2->x * a1.x + a1.y * v2->y + a1.z * v2->z + offset_x)*DVal;
y2 = (v2->x * a2.x + a2.y * v2->y + a2.z * v2->z + offset_y)*DVal;
z2 = v2->x * a3.x + a3.y * v2->y + a3.z * v2->z + offset_z;
if(z1 !=0 && z2 !=0){
WorldToDevice(x1/z1,y1/z1,&xpc1,&ypc1);
WorldToDevice(x2/z2,y2/z2,&xpc2,&ypc2);
}
else{
WorldToDevice(x1,y1,&xpc1,&ypc1);
WorldToDevice(x2,y2,&xpc2,&ypc2);
}
line(xpc1,ypc1,xpc2,ypc2);
}
else {
World2DToDevice(*v1,&xpc1, &ypc1);
World2DToDevice(*v2,&xpc2, &ypc2);
line(xpc1,ypc1,xpc2,ypc2);
}
}
void drawpoint3D(POINT3D *v1)
{
float x1, y1, z1;
int xpc1,ypc1;
if (ViewPort ==3) {
x1 = (v1->x * a1.x + a1.y * v1->y + a1.z * v1->z + offset_x)*DVal;
y1 = (v1->x * a2.x + a2.y * v1->y + a2.z * v1->z + offset_y)*DVal;
z1 = v1->x * a3.x + a3.y * v1->y + a3.z * v1->z + offset_z;
if(z1 !=0 ) WorldToDevice(x1/z1,y1/z1,&xpc1,&ypc1);
else WorldToDevice(x1,y1,&xpc1,&ypc1);
circle(xpc1,ypc1,5);
}
else {
World2DToDevice(*v1,&xpc1, &ypc1);
circle(xpc1,ypc1,5);
}
}
void drawsphere (int WinNum, POINT3D pc,float R)
{
POINT3D p1,p2;
float v, u;
int COUNT;
if (WinNum == 2) {
v = 0;
COUNT = 0;
for(u=DegToRad(0);u<=DegToRad(360);u+=DegToRad(15)) {
p1.x = R * cos(u);
p1.z = R * sin(u);
p1.y = 0;
p1.x = pc.x + p1.x;
p1.y = pc.y + p1.y;
p1.z = pc.z + p1.z;
if( COUNT == 0) {
p2 = p1;
COUNT++;
}
else {
drawline3D(&p1, &p2);
p2 = p1;
}
}
}
if (WinNum == 0) {
u = 0;
COUNT = 0;
for(v=DegToRad(0);v<=DegToRad(360);v+=DegToRad(15)) {
p1.x = R * cos(v);
p1.z = 0;
p1.y = R * sin(v);
p1.x = pc.x + p1.x;
p1.y = pc.y + p1.y;
p1.z = pc.z + p1.z;
if( COUNT == 0) {
p2 = p1;
COUNT++;
}
else {
drawline3D(&p1, &p2);
p2 = p1;
}
}
}
if (WinNum == 1) {
u = DegToRad(90);
COUNT = 0;
for(v=DegToRad(0);v<=DegToRad(360);v+=DegToRad(15)) {
p1.x = 0;
p1.z = R * cos(v);
p1.y = R * sin(v);
p1.x = pc.x + p1.x;
p1.y = pc.y + p1.y;
p1.z = pc.z + p1.z;
if( COUNT == 0) {
p2 = p1;
COUNT++;
}
else {
drawline3D(&p1, &p2);
p2 = p1;
}
}
}
if (WinNum == 3) {
for(v=DegToRad(-90);v<=DegToRad(90);v+=DegToRad(30)) {
COUNT = 0;
for(u=DegToRad(0);u<=DegToRad(360+30);u+=DegToRad(30)) {
p1.x = R * cos(v) * cos(u);
p1.z = R * cos(v) * sin(u);
p1.y = R * sin(v);
p1.x = pc.x + p1.x;
p1.y = pc.y + p1.y;
p1.z = pc.z + p1.z;
if( COUNT == 0) {
p2 = p1;
COUNT++;
}
else {
drawline3D(&p1, &p2);
p2 = p1;
}
}
}
for(u=DegToRad(0);u<= DegToRad(360);u+=DegToRad(30)) {
COUNT = 0;
for(v=DegToRad(-90);v<=DegToRad(90+30);v+=DegToRad(30)) {
p1.x = R * cos(v) * cos(u);
p1.z = R * cos(v) * sin(u);
p1.y = R * sin(v);
p1.x = pc.x + p1.x;
p1.y = pc.y + p1.y;
p1.z = pc.z + p1.z;
if( COUNT == 0) {
p2 = p1;
COUNT++;
}
else {
drawline3D(&p1, &p2);
p2 = p1;
}
}
}
}
}
int IsMouse()
{
inregs.x.ax = 0;
int86(0x33,&inregs,&outregs);
return(outregs.x.ax ? outregs.x.bx : 0);
}
int MouseClick()
{
int click = 0;
inregs.x.ax = 5;
inregs.x.bx = 1;
int86(0x33,&inregs,&outregs);
click = outregs.x.bx << 1;
inregs.x.bx--;
int86(0x33,&inregs,&outregs);
return(click | outregs.x.bx);
}
void MouseXY(int *xpos,int *ypos)
{
inregs.x.ax = 3;
int86(0x33,&inregs,&outregs);
*xpos = outregs.x.cx;
*ypos = outregs.x.dx;
}
void MouseShow(int toggle)
{
if (toggle) inregs.x.ax = 1;
else inregs.x.ax = 2;
int86(0x33,&inregs,&outregs);
}
Icon CreateIcon(int xo,int yo,int width,int height,int color,char * text)
{
Icon temp;
temp.x = xo;
temp.y = yo;
temp.width = width;
temp.height = height;
temp.color = color;
strcpy(temp.str,text);
return(temp);
}
void DrawIcon(Icon ic)
{
int color;
color = getcolor();
MouseShow(0);
setcolor(0);
setfillstyle(1,ic.color);
bar3d(ic.x,ic.y,ic.x+ic.width,ic.y+ic.height,0,0);
rectangle(ic.x,ic.y,ic.x+ic.width,ic.y+ic.height);
rectangle(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+ic.height-1);
outtextxy(ic.x+2,ic.y + 5,ic.str);
setcolor(15);
line(ic.x,ic.y,ic.x+ic.width,ic.y);
line(ic.x,ic.y,ic.x,ic.y+ic.height);
line(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+1);
line(ic.x+1,ic.y+1,ic.x+1,ic.y+ic.height-1);
outtextxy(ic.x+1,ic.y + 4,ic.str);
MouseShow(1);
setcolor(color);
}
int IconCheck(Icon ikon,int xm,int ym)
{
if ((xm > ikon.x) && (xm < ikon.x + ikon.width) &&
(ym > ikon.y) && (ym < ikon.y + ikon.height))
return(1);
else return(0);
}
void CreateIconColumn(int xo,int yo,int width,int height,int color,
int spc, int num, Icon icon[],char **text)
{
int i,y;
y = yo;
for(i=0;i<num;i++) {
icon[i] = CreateIcon(xo,y,width,height,color,text[i]);
y += height + spc;
}
}
POINTint World3DToDevice(POINT3D v1)
{
float x1, y1, z1;
int xpc1,ypc1;
POINTint tmp;
if (ViewPort ==3) {
x1 = (v1.x * a1.x + a1.y * v1.y + a1.z * v1.z + offset_x)*DVal;
y1 = (v1.x * a2.x + a2.y * v1.y + a2.z * v1.z + offset_y)*DVal;
z1 = v1.x * a3.x + a3.y * v1.y + a3.z * v1.z + offset_z;
if(z1 !=0 ) WorldToDevice(x1/z1,y1/z1,&xpc1,&ypc1);
else WorldToDevice(x1,y1,&xpc1,&ypc1);
tmp.x = xpc1; tmp.y = ypc1; return (tmp);
}
else {
World2DToDevice(v1,&xpc1, &ypc1);
tmp.x = xpc1; tmp.y = ypc1; return (tmp);
}
}
void drawpolygon (POINT3D *poly, int size)
{
POINTint p[6], p12,p32;
int i, drawit, pp[14], count;
long sum;
if (SaveRAW) {
for (i=1;i <= size-2;i++)
fprintf (RAWfptr,"%g %g %g %g %g %g %g %g %g\n",
poly[0].x,poly[0].y,poly[0].z,
poly[i].x,poly[i].y,poly[i].z,
poly[i+1].x,poly[i+1].y,poly[i+1].z);
}
for (i = 0; i < size; i++)
p[i] = World3DToDevice(poly[i]);
for(i=0,count=0; i<2*size; i+=2,count++) {
pp[i] = p[count].x;
pp[i+1] = p[count].y;
}
pp[i] = pp[0]; pp[i+1] = pp[1];
if (!hide_backface)
drawit = 1; /* Draw everything */
else {
/* find the "average" normal to the polygon */
sum = 0;
for (i = 1; i <= size-2; i++) {
p12.x = p[i].x - p[0].x;
p12.y = p[i].y - p[0].y;
p32.x = p[i+1].x - p[0].x;
p32.y = p[i+1].y - p[0].y;
sum = sum + ((long)p12.x * (long)p32.y) -
((long)p12.y * (long)p32.x);
}
/* Only draw the front faces */
drawit = (sum > 0);
}
if (drawit)
fillpoly(size,pp);
}
/* Calculates the field strength of the blob at point 'p' */
float BlobFunc (POINT3D p)
{
POINT3D dist;
float field, r, r2, temp;
int i;
field = 0.0;
for (i = 1; i <= bnum; i++) {
dist.x = p.x - blobs[i].x;
dist.y = p.y - blobs[i].y;
dist.z = p.z - blobs[i].z;
r = dist.x*dist.x + dist.y*dist.y + dist.z*dist.z;
r2 = blobs[i].radius * blobs[i].radius;
if (r < r2) {
temp = (1.0 - r/r2);
field += blobs[i].strength * temp*temp;
}
}
return (field - threshold);
}
/* Allocate memory for the marching cubes algorithm */
int AllocateCubes()
{
int i;
level0 = malloc ((y_steps+1) * sizeof(SAMPLE *));
if (level0 == NULL)
return 0;
for (i = 0; i < y_steps+1; i++) {
level0[i] = malloc ((z_steps+1) * sizeof(SAMPLE));
if (level0[i] == NULL)
return 0;
}
level1 = malloc ((y_steps+1) * sizeof(SAMPLE *));
if (level1 == NULL)
return 0;
for (i = 0; i < y_steps+1; i++) {
level1[i] = malloc ((z_steps+1) * sizeof(SAMPLE));
if (level1[i] == NULL)
return 0;
}
return 1;
}
void FreeCubes()
{
int i;
for (i = 0; i < y_steps+1; i++)
free (level0[i]);
free (level0);
for (i = 0; i < y_steps+1; i++)
free (level1[i]);
free (level1);
}
void SampleLevel (SAMPLE **level, int ix,
POINT3D *vmin, POINT3D *vmax)
{
POINT3D v;
int iy, iz;
v.x = (float)ix/x_steps * vmin->x +
(1.0 - (float)ix/x_steps)*vmax->x;
for (iy = 0; iy <= y_steps; iy++) {
v.y = (float)iy/y_steps * vmin->y +
(1.0 - (float)iy/y_steps)*vmax->y;
for (iz = 0; iz <= z_steps; iz++) {
v.z = (float)iz/z_steps * vmin->z +
(1.0 - (float)iz/z_steps)*vmax->z;
level[iy][iz].loc = v;
level[iy][iz].value = BlobFunc (v);
}
}
}
/* Break the blob up into a mesh and display it */
int CreateBlobs()
{
int i, ix, iy, iz;
BLOB b;
SAMPLE **temp;
POINT3D vmin = {+1e30, +1e30, +1e30};
POINT3D vmax = {-1e30, -1e30, -1e30};
clearviewport();
setfillstyle(1,7);
/* Find the extents of the shape */
for (i = 1; i <= bnum; i++) {
b = blobs[i];
if (b.x - b.radius < vmin.x) vmin.x = b.x - b.radius;
if (b.x + b.radius > vmax.x) vmax.x = b.x + b.radius;
if (b.y - b.radius < vmin.y) vmin.y = b.y - b.radius;
if (b.y + b.radius > vmax.y) vmax.y = b.y + b.radius;
if (b.z - b.radius < vmin.z) vmin.z = b.z - b.radius;
if (b.z + b.radius > vmax.z) vmax.z = b.z + b.radius;
}
if (!AllocateCubes()) {
closegraph();
printf("Not enough memory for marching cubes.");
exit(1);
}
SampleLevel (level0, 0, &vmin, &vmax);
for (ix = 1; ix <= x_steps; ix++) {
SampleLevel (level1, ix, &vmin, &vmax);
for (iy = 0; iy < y_steps; iy++)
for (iz = 0; iz < z_steps; iz++)
CubeIntersect (iy, iz);
temp = level0;
level0 = level1;
level1 = temp;
}
FreeCubes();
return 1;
}
void CubeIntersect (int iy, int iz)
{
SAMPLE cube[8];
int i, j, polysize, numline;
PAIR3D line[12], temp;
POINT3D poly[12];
cube[0] = level0[iy][iz];
cube[1] = level1[iy][iz];
cube[2] = level0[iy+1][iz];
cube[3] = level1[iy+1][iz];
cube[4] = level0[iy][iz+1];
cube[5] = level1[iy][iz+1];
cube[6] = level0[iy+1][iz+1];
cube[7] = level1[iy+1][iz+1];
/* Analyze each of the 6 faces of the cube one at a time. For
each face that was intersected save the intersection line */
numline = 0;
FaceIntersect (cube, 0, 1, 3, 2, line, &numline);
FaceIntersect (cube, 4, 6, 7, 5, line, &numline);
FaceIntersect (cube, 0, 2, 6, 4, line, &numline);
FaceIntersect (cube, 1, 5, 7, 3, line, &numline);
FaceIntersect (cube, 0, 4, 5, 1, line, &numline);
FaceIntersect (cube, 2, 3, 7, 6, line, &numline);
if (numline > 0) {
/* Sort the line segments into polygons */
polysize = 0;
for (i = 0; i < numline; i++) {
poly[polysize++] = line[i].p1;
for (j = i+1; j < numline; j++) {
if (equal (&line[j].p1, &line[i].p2)) {
temp = line[j];
line[j] = line[i+1];
line[i+1] = temp;
break;
}
}
if (j >= numline) {
drawpolygon (poly, polysize);
polysize = 0;
}
}
}
}
/* Analyze a cube face for blob intersections. Intersections are
detected by looking for positive to negative field strength
changes between adjacent corners. If an intersection is found
then the coords of the line segment(s) are added to array line
and *numline is increased */
void FaceIntersect (SAMPLE *cube, int a, int b, int c, int d,
PAIR3D *line, int *numline)
{
POINT3D points[4], vcenter;
float center;
int sign[4];
int l1, l2, l3, l4;
int index = 0;
/* Check face edge a-b */
if (cube[a].value * cube[b].value < 0.0) {
sign[index] = (cube[b].value >= 0.0);
EdgeIntersect (&points[index++], &cube[a], &cube[b]);
}
/* Check face edge b-c */
if (cube[b].value * cube[c].value < 0.0) {
sign[index] = (cube[c].value >= 0.0);
EdgeIntersect (&points[index++], &cube[b], &cube[c]);
}
/* Check face edge c-d */
if (cube[c].value * cube[d].value < 0.0) {
sign[index] = (cube[d].value >= 0.0);
EdgeIntersect (&points[index++], &cube[c], &cube[d]);
}
/* Check face edge d-a */
if (cube[d].value * cube[a].value < 0.0) {
sign[index] = (cube[a].value >= 0.0);
EdgeIntersect (&points[index++], &cube[d], &cube[a]);
}
/* One line segment */
if (index == 2) {
if (sign[0] > 0) { /* Get the line direction right */
line[*numline].p1 = points[0];
line[*numline].p2 = points[1];
}
else {
line[*numline].p1 = points[1];
line[*numline].p2 = points[0];
}
(*numline)++;
}
/* Two line segments */
else if (index == 4) {
/* Sample the center of the face to determine which points
to connect */
vcenter = add (&cube[a].loc, &cube[b].loc);
vcenter = add (&vcenter, &cube[c].loc);
vcenter = add (&vcenter, &cube[d].loc);
vcenter = multiply (&vcenter, 0.25);
center = BlobFunc(vcenter);
/* Does the sign of the center sample match the
sign of the upper left corner? */
if ((center >= 0.0) != sign[0])
{ l1 = 0; l2 = 1; l3 = 2; l4 = 3; }
else
{ l1 = 1; l2 = 2; l3 = 3; l4 = 0; }
if (sign[l1] > 0) { /* Get the line direction right */
line[*numline].p1 = points[l1];
line[*numline].p2 = points[l2];
}
else {
line[*numline].p1 = points[l2];
line[*numline].p2 = points[l1];
}
(*numline)++;
if (sign[l3] > 0) {
line[*numline].p1 = points[l3];
line[*numline].p2 = points[l4];
}
else {
line[*numline].p1 = points[l4];
line[*numline].p2 = points[l3];
}
(*numline)++;
}
}
void EdgeIntersect (POINT3D *v, SAMPLE *a, SAMPLE *b)
{
POINT3D vtemp;
if (a->value > b->value) {
vtemp = subtract (&a->loc, &b->loc);
vtemp = multiply (&vtemp, a->value/(a->value - b->value));
*v = subtract (&a->loc, &vtemp);
}
else {
vtemp = subtract (&b->loc, &a->loc);
vtemp = multiply (&vtemp, b->value/(b->value - a->value));
*v = subtract (&b->loc, &vtemp);
}
}